package productservice

import (
	"context"
	"fmt"
	"gitee.com/monkeyPP/happy-mall/services/productservice/internal/infrastructure/search"
	"path/filepath"
	"runtime"

	"github.com/elastic/go-elasticsearch/v9"
	"github.com/samber/do/v2"
	"github.com/spf13/cobra"

	"gitee.com/monkeyPP/happy-mall/pkg/es"
	"gitee.com/monkeyPP/happy-mall/pkg/log"
	"gitee.com/monkeyPP/happy-mall/pkg/version/verflag"
	"gitee.com/monkeyPP/happy-mall/services/productservice/internal/infrastructure/eventbus"
	"gitee.com/monkeyPP/happy-mall/services/productservice/internal/infrastructure/server"
	"gitee.com/monkeyPP/happy-mall/services/productservice/internal/initialize"
)

func NewProductServiceCommand() *cobra.Command {
	cmd := &cobra.Command{
		// 指定命令的名字，该名字会出现在帮助信息中
		Use: "product-service",
		// 命令的简短描述
		Short: "A good Go practical project",
		// 命令的详细描述
		Long: `A good Go practical project, used to create user with basic information.`,
		// 命令出错时，不打印帮助信息。不需要打印帮助信息，设置为 true 可以保持命令出错时一眼就能看到错误信息
		SilenceUsage: true,
		// 指定调用 cmd.Execute() 时，执行的 Run 函数，函数执行失败会返回错误信息
		RunE: func(cmd *cobra.Command, args []string) error {

			// 如果 `--version=true`，则打印版本并退出
			verflag.PrintAndExitIfRequested()

			// 初始化日志
			log.Init()
			defer log.Sync() // Sync 将缓存中的日志刷新到磁盘文件中

			return run(initialize.GetInjector())
		},
		// 这里设置命令运行时，不需要指定命令行参数
		Args: func(cmd *cobra.Command, args []string) error {
			for _, arg := range args {
				if len(arg) > 0 {
					return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args)
				}
			}
			return nil
		},
	}

	// 初始化工作
	cobra.OnInitialize(
		initialize.LoadConfig, // 初始化配置文件
		initialize.Inject,     // 初始化依赖注入
		//initialize.InitTracing, // 初始化 jaeger
	)

	// 添加 -- version 标志
	verflag.AddFlags(cmd.PersistentFlags())

	return cmd
}

func run(i do.Injector) error {
	eventBus := do.MustInvoke[eventbus.EventBus](i)
	go func() {
		searchService := do.MustInvoke[search.SearchService](i)
		_ = eventBus.Subscribe(&eventbus.AddProductEvent{}, searchService.IndexProduct)
		err := eventBus.Start(context.Background())
		if err != nil {
			panic(err)
		}
	}()

	_, filename, _, ok := runtime.Caller(0)
	if !ok {
		panic("无法获取当前文件路径")
	}
	// 源代码文件所在目录（如 ./cmd/main.go -> ./cmd）
	currentDir := filepath.Dir(filename)
	projectRootDir := filepath.Join(currentDir, "..")
	esClient := do.MustInvoke[*elasticsearch.Client](i)
	err := es.InitIndex(esClient, projectRootDir)
	if err != nil {
		panic(err)
	}

	serverManager := do.MustInvoke[*server.Manager](i)
	err = serverManager.Start()
	if err != nil {
		panic(err)
	}
	return nil
}
